package com.gitee.wsl.net

import kotlinx.io.IOException

object Net{
    /**
     * 默认最小端口，1024
     */
    const val PORT_RANGE_MIN: Int = 1024
    /**
     * 默认最大端口，65535
     */
    const val PORT_RANGE_MAX: Int = 0xFFFF

    /**
     * 是否为有效的端口<br></br>
     * 此方法并不检查端口是否被占用
     *
     * @param port 端口号
     * @return 是否有效
     */
    fun isValidPort(port: Int): Boolean {
        // 有效端口是0～65535
        return port >= 0 && port <= PORT_RANGE_MAX
    }

    /**
     * 查找1024~65535范围内的可用端口<br></br>
     * 此方法只检测给定范围内的随机一个端口，检测65535-1024次<br></br>
     * 来自org.springframework.util.SocketUtils
     *
     * @return 可用的端口
     * @since 4.5.4
     */
    fun getUsableLocalPort(): Int {
        return getUsableLocalPort(PORT_RANGE_MIN)
    }

    /**
     * 查找指定范围内的可用端口，最大值为65535<br></br>
     * 此方法只检测给定范围内的随机一个端口，检测65535-minPort次<br></br>
     * 来自org.springframework.util.SocketUtils
     *
     * @param minPort 端口最小值（包含）
     * @return 可用的端口
     * @since 4.5.4
     */
    fun getUsableLocalPort(minPort: Int): Int {
        return getUsableLocalPort(minPort, PORT_RANGE_MAX)
    }

    /**
     * 查找指定范围内的可用端口<br></br>
     * 此方法只检测给定范围内的随机一个端口，检测maxPort-minPort次<br></br>
     * 来自org.springframework.util.SocketUtils
     *
     * @param minPort 端口最小值（包含）
     * @param maxPort 端口最大值（包含）
     * @return 可用的端口
     * @since 4.5.4
     */
    fun getUsableLocalPort(minPort: Int, maxPort: Int): Int {
        val maxPortExclude = maxPort + 1
        var randomPort: Int
        for (i in minPort..<maxPortExclude) {
            randomPort = (minPort..maxPortExclude).random()
            if (isUsableLocalPort(randomPort)) {
                return randomPort
            }
        }

        throw Exception("Could not find an available port in the range [$minPort, $maxPort] after {$(maxPort - minPort)} attempts")
    }

    /**
     * 检测本地端口可用性<br></br>
     * 来自org.springframework.util.SocketUtils
     *
     * @param port 被检测的端口
     * @return 是否可用
     */
    fun isUsableLocalPort(port: Int): Boolean {
        if (!isValidPort(port)) {
            // 给定的IP未在指定端口范围中
            return false
        }

        // issue#765@Github, 某些绑定非127.0.0.1的端口无法被检测到
//        try {
//            ServerSocket(port).use { ss ->
//                ss.setReuseAddress(true)
//            }
//        } catch (ignored: IOException) {
//            return false
//        }
//
//        try {
//            DatagramSocket(port).use { ds ->
//                ds.setReuseAddress(true)
//            }
//        } catch (ignored: IOException) {
//            return false
//        }

        return true
    }

    /**
     * 获取多个本地可用端口<br></br>
     * 来自org.springframework.util.SocketUtils
     *
     * @param numRequested 尝试次数
     * @param minPort      端口最小值（包含）
     * @param maxPort      端口最大值（包含）
     * @return 可用的端口
     * @since 4.5.4
     */
    fun getUsableLocalPorts(numRequested: Int, minPort: Int, maxPort: Int): MutableSet<Int> {
        val availablePorts = mutableSetOf<Int>()
        var attemptCount = 0
        while ((++attemptCount <= numRequested + 100) && availablePorts.size < numRequested) {
            availablePorts.add(getUsableLocalPort(minPort, maxPort))
        }

        if (availablePorts.size != numRequested) {
            throw Exception("Could not find $numRequested available  ports in the range {$(maxPort - minPort)}")
        }

        return availablePorts
    }

}